package com.wits.democamera;

import android.Manifest;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.Build;
import android.os.Environment;
import android.preference.PreferenceManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import com.wits.PreferenceUtil;
import com.wits.av.MFormat;
import com.wits.av.MRecord;
import com.wits.av.MRecordQuery;
import com.wits.av.MediaType;
import com.wits.av.PsCaster;
import com.wits.av.PsCasterListener;
import com.wits.av.RecordCaster;
import com.wits.av.RecordCasterTranport;
import com.wits.av.RtpSound;
import com.wits.media.COsdOverlayMixer;
import com.wits.media.CPsCamera;
import com.wits.media.ImageFrame;
import com.wits.media.ImageFrameUtil;
import com.wits.media.OsdOverlay;
import com.wits.media.PsCamera;
import com.wits.util.NetUtil;


public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback, PsCasterListener {

    private static final int RESULT_SETTINGS = 100;
    private static final int PERMISSIONS_REQUEST_CODE = 201;


    private static final String TAG = "PsCamera";


    private PsCamera    psCamera;
    private SurfaceView surfaceView;

    private RtpSound  rtpSound;

    private CameraRecorder recorder = new CameraRecorder();

    private RecordCaster    recordCaster;
    private int     casterChannel = RecordCaster.INVALID_CHANNEL;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        setupUI();

        checkPermissions();

        recorder.open();
        setupRecordCaster();
    }

    @Override
    protected void onDestroy() {

        stopCapture();

        recorder.close();
        teardownRecordCaster();

        super.onDestroy();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            Intent i = new Intent(this, SettingsActivity.class);
            startActivityForResult(i, RESULT_SETTINGS);
            return true;
        } else if (id == R.id.action_exit) {
            finish();
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        //Log.i(TAG, "code: " + requestCode + " " + permissions);

        if (requestCode == PERMISSIONS_REQUEST_CODE) {
            if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
                showToast("权限不足.");
            }
        }

    }


    private void setupUI() {
        surfaceView = (SurfaceView)findViewById(R.id.surfaceView);

        surfaceView.getHolder().addCallback(this);

        updateStartButton(isStarted());
    }


    public void onClickStart(View view) {

        if (isStarted()) {
            stopCapture();
        } else {
            startCapture();
        }

        updateStartButton(isStarted());
    }

    public void updateStartButton(boolean started) {
        Button button = (Button)findViewById(R.id.buttonStart);
        button.setText(started ? "Stop" : "Start");
    }

    public void testOverlay() {
        BitmapFactory.Options options = new BitmapFactory.Options();
        Bitmap videoBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.sand, options);
        ImageFrame videoFrame = ImageFrameUtil.makeYv12(videoBitmap);

        COsdOverlayMixer mixer = new COsdOverlayMixer();
        OsdOverlay overlay = new OsdOverlay();
        overlay.font.size = 16;
        overlay.text = "x哈哈x";
        overlay.color = Color.rgb(255, 0, 0);
        overlay.font.italic = true;
        mixer.setOverlay(0, overlay);

        mixer.draw(videoFrame);

        String filepath = makePath(formatName(videoBitmap, "out", ".yv12"));
        ImageFrameUtil.save(videoFrame, filepath);
    }

    public String makePath(String name) {
        String filepath = Environment.getExternalStorageDirectory().getAbsolutePath();
        return filepath + "/Download/" + name;
    }

    public String formatName(Bitmap bitmap, String prefix, String ext) {
        return prefix + '_' + Integer.toString(bitmap.getWidth()) + '-' + Integer.toString(bitmap.getHeight()) + ext;
    }


    private void showToast(int messageId) {
        showToast(getString(messageId));
    }

    private void showToast(String message) {
        showToast(message, Toast.LENGTH_LONG);
    }

    private void showToast(String message, int duration) {
        try {
            Toast.makeText(getApplicationContext(), message, duration).show();
        } catch (Throwable t) {
            //
        }
    }

    private void checkPermissions() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            requestPermissions(new String[] {
                    Manifest.permission.CAMERA,
                    Manifest.permission.RECORD_AUDIO,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE,
                    Manifest.permission.INTERNET,
                    Manifest.permission.ACCESS_NETWORK_STATE,
                    Manifest.permission.ACCESS_WIFI_STATE
            }, PERMISSIONS_REQUEST_CODE);
        }
    }


    public void startCapture() {
        SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
        String ip = sharedPrefs.getString("ip", "192.168.3.53");
        int port = PreferenceUtil.getPrefInt(sharedPrefs, "port", 10000);
        int payload = PreferenceUtil.getPrefInt(sharedPrefs, "payload", 96);
        int ssrc = 0x02;
        /// RTP上传输PS/ES模式
        boolean esMode = false;

        MFormat fmt = new MFormat();
        fmt.width = 640;
        fmt.height = 480;
        fmt.codec = MediaType.MCODEC_H265;
        fmt.fps = 25;
        fmt.gop = 1;
        fmt.bitrate = 1000 * 1000 * 1;

        fmt.audioCodec = MediaType.MCODEC_G711U;
        fmt.channels = 1;
        fmt.sampleRate = 8000;


        psCamera = new CPsCamera();
        psCamera.setFormat(fmt);

        configOsd();

        psCamera.setProtocol(PsCamera.PROTOCOL_RTP_TCP, payload, ssrc, esMode);

        int cameraId = 0;
        if (psCamera.open(cameraId, surfaceView.getHolder())) {

            psCamera.setCasterEventCallback(this);

            psCamera.setDestination(ip, port);

            psCamera.start();
        }
    }

    public void stopCapture() {
        if (psCamera != null) {
            psCamera.stop();
            psCamera.close();
            psCamera = null;
        }
    }

    public boolean isStarted() {
        return (psCamera != null) && psCamera.isStarted();
    }

    void configOsd() {
        SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
        String osdText = sharedPrefs.getString("osd_text", "xy信通abc11");

        OsdOverlay overlay = new OsdOverlay();

        overlay.font.size = 36;
        overlay.font.italic = true;

        overlay.color = Color.rgb(0, 255, 0);
        overlay.flags = OsdOverlay.ANTI_ALIAS_FLAG;
        overlay.background = Color.rgb(127, 127, 0);
        overlay.alpha = 127;
        overlay.transparent = false;
        overlay.text = osdText;

        overlay.left = 0;
        overlay.top = 0;

        psCamera.setOsd(0, overlay);

        OsdOverlay dateOverlay = new OsdOverlay();
        dateOverlay.setDateTime("yyyy-MM-dd HH:mm:ss");
        dateOverlay.top = 100;
        dateOverlay.left = 20;
        dateOverlay.font.size = 36;
        dateOverlay.color = Color.rgb(0, 0, 255);
        psCamera.setOsd(1, dateOverlay);

//        OsdOverlay imageOverlay = new OsdOverlay();
//        imageOverlay.setImage(this, R.mipmap.ic_launcher);
//        imageOverlay.top = 200;
//        imageOverlay.left = 0;
//        imageOverlay.font.size = 36;
//        imageOverlay.color = Color.rgb(0, 0, 255);
//        psCamera.setOsd(2, imageOverlay);
    }



    @Override
    public void surfaceCreated(SurfaceHolder surfaceHolder) {
        Log.i(TAG, "Main surfaceCreated");
    }

    @Override
    public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
        Log.i(TAG, "Main surfaceChanged. width: " + i1);
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
        Log.i(TAG, "Main surfaceDestroyed");
    }

    public void startTalk() {
        stopTalk();

        rtpSound = new RtpSound();
        rtpSound.open(10000, MediaType.MCODEC_G711U, 1, 8000);

        String ip = NetUtil.getLocalAddr(this);
        Log.i(TAG, ip);
    }

    public void stopTalk() {
        if (rtpSound != null) {
            try {
                rtpSound.close();
            } catch (Throwable throwable) {
                //
            }

            rtpSound = null;
        }
    }

    public boolean isTalking() {
        return rtpSound != null;
    }

    public void onClickTalk(View view) {

        if (isTalking()) {
            stopTalk();
        } else {
            startTalk();
        }

        updateTalkButton(isTalking());
    }

    public void updateTalkButton(boolean started) {
        Button button = (Button)findViewById(R.id.buttonTalk);
        button.setText(started ? "Stop Talk" : "Start Talk");
    }


    public void startRecord() {
        if (!isStarted()) {
            return;
        }

        int recordType = 1;
        recorder.startRecord(psCamera, recordType);
    }

    public void stopRecord() {
        recorder.stopRecord();
    }

    public boolean isRecording() {
        return recorder.isRecording();
    }

    public void onClickRecord(View view) {
        if (isRecording()) {
            stopRecord();
        } else {
            startRecord();
        }
        updateRecordButton(isRecording());
    }

    public void updateRecordButton(boolean started) {
        Button button = (Button)findViewById(R.id.buttonRecord);
        button.setText(started ? "Stop Rec" : "Start Rec");
    }


    public void onClickQuery(View view) {

        MRecord[] records = new MRecord[128];
        int count = recorder.findRecord(records);

        for (int i = 0; i < count; i ++) {
            if (records[i] == null) {
                break;
            }
            Log.i(TAG, "" + records[i]);
        }
    }


    public void onClickPlayback(View view) {
        closePlayback();

        MRecordQuery query = new MRecordQuery();

        MRecord[] records = new MRecord[4];
        int count = recordCaster.findRecord(query, 0, records);

        for (int i = 0; i < count; i ++) {
            if (records[i] == null) {
                break;
            }
            Log.i(TAG, "" + records[i]);
        }

        RecordCasterTranport tranport = new RecordCasterTranport();
        tranport.protocol = PsCaster.PROTOCOL_RTP_UDP;
        tranport.ssrc = 1;
        tranport.payload = 96;

        double scale = 1.0;
        casterChannel = recordCaster.openFile(tranport, records, 0, scale);
        if (casterChannel != RecordCaster.INVALID_CHANNEL) {
            recordCaster.addTarget(casterChannel, "192.168.3.53", 10000);
            recordCaster.start(casterChannel);
        } else {
            Log.e(TAG, "failed to open RecordCaster.");
        }
    }

    public void closePlayback() {
        if (casterChannel < 0) {
            return;
        }

        recordCaster.stop(casterChannel);
        recordCaster.close(casterChannel);
        casterChannel = RecordCaster.INVALID_CHANNEL;
    }

    public void setupRecordCaster() {
        recordCaster = new RecordCaster();
        String dbpath = CameraRecorder.getDbPath();
        if (!recordCaster.openRecordStore(dbpath)) {
            Log.e(TAG, "failed to open db. " + dbpath);
        }
    }

    public void teardownRecordCaster() {
        try {
            recordCaster.close();
            recordCaster = null;
        } catch (Throwable throwable) {

        }
    }


    @Override
    public void onCasterEvent(int handle, int event) {
        Log.i(TAG, "onCasterEvent. " + handle + "," + event);

        if (event == PsCaster.PSCASTER_EVENT_DISCONNECTED) {
            /// 连接断开了

            Log.i(TAG, "disconnected.");
        }
    }

}
